<template>
    <div>
        <h2
            v-for="(text, index) in textArr"
            :key="index"
            :id="'column' + index"
            :class="{ typing: isAnimation, lastTyping: isLast }"
        >
            {{ text }}
        </h2>
    </div>
</template>
<script lang="ts">
import { Vue, Component, Prop } from 'vue-property-decorator';

// 打字动画
@Component
export default class TypingAnimation extends Vue {
    @Prop({
        default: '',
        type: String,
    })
    private text!: string;

    private isAnimation: boolean = false;
    private isLast: boolean = false;

    private textArr: string[] = [];

    private mounted() {
        this.CommaSegmentation();
        const that = this;
        for (let index = 0; index < this.textArr.length; index++) {
            const element = this.textArr[index];
            const textDom = document.getElementById('column' + index);
            ((j: number) => {
                setTimeout(() => {
                    that.flowAnimation(element, index);
                }, j * 3000);
            })(index); // 使用立即执行函数解决setTimeout函数的闭包问题，详细讲解请参考，《你不知道的JavaScript（上卷）》：第三章：3.3.2
        }
    }

    private flowAnimation(element: string, index: number) {
        this.$nextTick(() => {
            const textDom = document.getElementById('column' + index);
            if (textDom) {
                textDom.classList.add('typing');
                const len = this.getTextLength(element);
                textDom.style.width = len + len * 0.1 + 'ch';
                textDom.addEventListener('animationend', changeStyle, false);

                function changeStyle() {
                    if (textDom) {
                        textDom.style.borderRight = 'none';
                    }
                }
            }
        });
    }

    // 逗号分隔
    private CommaSegmentation() {
        this.textArr = this.text.split('，');
    }

    // 字符等分
    private EqualDivision() {
        if (this.text.length > 100) {
            const column = Math.floor(this.text.length / 40); // 行数
            const lastColumn = this.text.length % 40;

            for (let index = 0; index < column; index++) {
                const element = this.text.slice(
                    index * 40,
                    index > 0 ? 40 * (index + 1) : 40,
                );

                this.textArr.push(element);
                this.trimSpace(this.textArr);
            }
            if (lastColumn) {
                this.textArr.push(
                    this.text.slice(40 * column, this.text.length),
                );
            }
        }
    }

    // 获取文本长度，计算动画设置宽度
    private getTextLength(element: string) {
        let len = 0;
        for (let i = 0; i < element.length; i++) {
            if (element.charCodeAt(i) > 127 || element.charCodeAt(i) === 94) {
                len += 2;
            } else {
                len++;
            }
        }
        return len;
    }

    // 删除数组空白元素
    private trimSpace(array: string[]) {
        for (let i = 0; i < array.length; i++) {
            if (
                array[i] === '' ||
                array[i] === null ||
                typeof array[i] === 'undefined'
            ) {
                array.splice(i, 1);
                i = i - 1;
            }
        }
        return array;
    }
}
</script>
<style scoped>
@keyframes typing {
    from {
        width: 0;
    }
}
@keyframes caret {
    50% {
        border-color: transparent;
    }
}
h2 {
    overflow: hidden;
    white-space: nowrap;
    border-right: 0.05em solid;
    display: none;
    color: #42b983;
}

.typing {
    overflow: hidden;
    white-space: nowrap;
    border-right: 0.05em solid;
    display: block;
    animation: typing 3s steps(35), caret 1s steps(1) infinite;
}
div {
    display: flex;
    flex-direction: column;
    align-items: center;
}
</style>